#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define MAX_SIZE 1024

//采用POSIX信号量实现生产者消费者模型
//生产者和生产者之间为互斥关系 
//消费者和消费者之间为互斥关系
//生产者和消费这之间为同步互斥关系


//******************实现一个交易场所******************
//循环队列

typedef struct Queue
{
  int data[MAX_SIZE];
  size_t size;
  int start;
  int end;
}Queue;

Queue que;//一个全局的队列，作为交易场所
int count;//一个全局的变量，作为生产的物品
  sem_t sem_b,sem_s,sem_c;

void QueueInit(Queue * que)
{
  if(que!=NULL)
  {
    que->size=que->start=que->end=0;
  }
}

void QueuePush(Queue * que,int value)
{
  if(que!=NULL)
  {
    if(que->size>=MAX_SIZE)
    {
      return;
    }
    else
    {
      que->data[que->end]=value;
      que->end++;
      if(que->end>=MAX_SIZE)
      {
        que->end-=MAX_SIZE;
      }
      que->size++;
    }
  }
}

void QueuePop(Queue * que,int * tmp)
{
  if(que!=NULL)
  {
    if(que->size==0)
    {
      return;
    }
    else
    {
      *tmp=que->data[que->start];
      que->start++;
      if(que->start>=MAX_SIZE)
      {
        que->start-=MAX_SIZE;
      }
      que->size--;
    }
  }
}


  //实现三种关系
  void * Product(void * arg)
  {
  (void)arg;
  while(1)
  {
    sem_wait(&sem_b);//空位的个数减一,如果sem_b为0，则进行等待消费者消费（队列满）

    sem_wait(&sem_c);//等待信号量，将信号量值减一(实现互斥锁)
    QueuePush(&que,++count); 
    printf("生产：%d\n",count);
    sem_post(&sem_c);//发布信号量，将信号量值加一（实现互斥锁）

    sem_post(&sem_s);//元素的个数加一，通知消费者来消费，实现生产者和消费者之间的同步关系
    sleep(1);
  }
  return NULL;
}

void * Consume(void * arg)
{
  (void)arg;
  while(1)
  {
    int tmp=-1;
    sem_wait(&sem_s);//将元素个数减一，如果sem_s为0，则进行等待生产者生产（队列空）

    sem_wait(&sem_c);//等待信号量，将信号量值减一(实现互斥锁)
    QueuePop(&que,&tmp); 
    printf("消费：%d \n",tmp);
    sem_post(&sem_c);//发布信号量，将信号量值加一（实现互斥锁）

    sem_post(&sem_b);//将空白个数加一，实现生产者和消费者之间的同步关系
    sleep(1);
  }
  return NULL;
}


//实现两种角色
void test()
{
  const int N=5;
  pthread_t thread[N];

  //初始化信号量
  sem_init(&sem_s,0,0);//元素的个数
  sem_init(&sem_b,0,MAX_SIZE);//空位的个数
  sem_init(&sem_c,0,1);//二元信号量，互斥锁

  //初始化队列
  QueueInit(&que);

  int i=0;
  //创建线程
  for(i=0;i<N/2;i++)
  {
    pthread_create(&thread[i],NULL,Product,NULL);
  }
  for(i=0;i<N-N/2;++i)
  {
    pthread_create(&thread[i],NULL,Consume,NULL);
  }

  //等待线程
  for(i=0;i<N;++i)
  {
    pthread_join(thread[i],NULL);
  }

  //销毁信号量 
  sem_destroy(&sem_b);
  sem_destroy(&sem_s);
  sem_destroy(&sem_c);
}

int main()
{
  test();
  return 0;
}
